package com.project.shiro.util.redis;

import com.project.common.core.utils.ByteUtil;
import com.project.common.core.utils.redis.RedisClient;
import com.project.common.core.utils.redis.RedisConsts;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.util.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;

public class ShiroRedisCache<K, V> implements Cache<K, V> {

    //初始化Log日志
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    //注入redisClient实例
    @Resource(name = "redisClient")
    private RedisClient redisClient;

    //shiroSession的key值前缀
    private String keyPrefix;

    //通过redisClient实例和prefix参数构造redisCache
    public ShiroRedisCache(RedisClient redisClient, String prefix) {
        if (redisClient == null) {
            throw new IllegalArgumentException("shiroRedisCahe初始化时，redisClient参数不能为空");
        }
        this.redisClient = redisClient;
        this.keyPrefix = prefix;
    }

    /**
     * 获得String类型的KEY
     *
     * @param key
     * @return
     */
    private String getPreStringKey(K key) {
        String preKey = null;
        if (key instanceof String) {
            preKey = this.keyPrefix + key;
            return preKey;
        } else {
            try {
                preKey = keyPrefix + ByteUtil.bytesToHexString(ByteUtil.objectToBytes(key));
            } catch (IOException e) {
                e.printStackTrace();
            }
            return preKey;
        }
    }

    @Override
    public V get(K key) throws CacheException {
        logger.debug("根据key从Redis中获取对象 key [" + key + "]");
        try {
            if (key == null) {
                return null;
            } else {
                V Vvalue = (V) redisClient.get(getPreStringKey(key));
                if (Vvalue == null) {
                    return null;
                }
                return Vvalue;
            }
        } catch (Throwable t) {
            throw new CacheException(t);
        }

    }

    @Override
    public V put(K key, V value) throws CacheException {
        logger.debug("根据key从存储 key [" + key + "]");
        try {
            redisClient.set(getPreStringKey(key), value);
            redisClient.setAndExpire(getPreStringKey(key), value, RedisConsts.ADMIN_SHIRO_REALM_EXPIRE);
            return value;
        } catch (Throwable t) {
            throw new CacheException(t);
        }
    }

    @Override
    public V remove(K key) throws CacheException {
        logger.debug("从redis中删除 key [" + key + "]");
        try {
            V previous = get(key);
            redisClient.del(getPreStringKey(key));
            return previous;
        } catch (Throwable t) {
            throw new CacheException(t);
        }
    }

    @Override
    public void clear() throws CacheException {
        logger.debug("从redis中删除所有元素");
        try {
//            redisClient.flushDB();
        } catch (Throwable t) {
            throw new CacheException(t);
        }
    }

    @Override
    public int size() {
//		try {
//			Long longSize = new Long(redisClient.dbSize());
//            return longSize.intValue();
//        } catch (Throwable t) {
//            throw new CacheException(t);
//        }
        return 0;
    }

    @SuppressWarnings("unchecked")
    @Override
    public Set<K> keys() {
        try {
            Set<byte[]> keys = redisClient.keys(ByteUtil.objectToBytes(this.keyPrefix + "*"));
            if (CollectionUtils.isEmpty(keys)) {
                return Collections.emptySet();
            } else {
                Set<K> newKeys = new HashSet<K>();
                for (byte[] key : keys) {
                    newKeys.add((K) key);
                }
                return newKeys;
            }
        } catch (Throwable t) {
            throw new CacheException(t);
        }
    }

    @Override
    public Collection<V> values() {
        try {
            Set<byte[]> keys = redisClient.keys(ByteUtil.objectToBytes(this.keyPrefix + "*"));
            if (!CollectionUtils.isEmpty(keys)) {
                List<V> values = new ArrayList<V>(keys.size());
                for (byte[] key : keys) {
                    @SuppressWarnings("unchecked")
                    V value = get((K) key);
                    if (value != null) {
                        values.add(value);
                    }
                }
                return Collections.unmodifiableList(values);
            } else {
                return Collections.emptyList();
            }
        } catch (Throwable t) {
            throw new CacheException(t);
        }
    }

    public String getKeyPrefix() {
        return keyPrefix;
    }

    public void setKeyPrefix(String keyPrefix) {
        this.keyPrefix = keyPrefix;
    }

    public RedisClient getRedisClient() {
        return redisClient;
    }

    public void setRedisClient(RedisClient redisClient) {
        this.redisClient = redisClient;
    }
}
